package com.hsd.znsh.security.app;

import com.hsd.znsh.security.pc.PCAuthenticationToken;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.security.authentication.*;
import org.springframework.security.authentication.dao.SaltSource;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;

public class APPAuthenticationProvider implements AuthenticationProvider {

	protected final Log logger = LogFactory.getLog(this.getClass());
	protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
	private PasswordEncoder passwordEncoder;
	private UserDetailsService userDetailsService;
	private SaltSource saltSource;

	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {

		APPAuthenticationToken authenticationToken = (APPAuthenticationToken) authentication;
		UserDetails user;
		try {
			 user = userDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal());
		} catch (Exception var7) {
			throw new InternalAuthenticationServiceException(var7.getMessage(), var7);
		}

		if (user == null) {
			throw new InternalAuthenticationServiceException("无法获取用户信息");
		}
		this.precheck(user);
		this.additionalAuthenticationChecks(user, (APPAuthenticationToken)authentication);
		this.postcheck(user);

		APPAuthenticationToken authenticationResult = new APPAuthenticationToken(user,authenticationToken.getCredentials(), user.getAuthorities());
		authenticationResult.setDetails(authenticationToken.getDetails());

		return authenticationResult;
	}


	@Override
	public boolean supports(Class<?> authentication) {
		return APPAuthenticationToken.class.isAssignableFrom(authentication);
	}


	private void precheck(UserDetails user) {
		if (!user.isAccountNonLocked()) {
			APPAuthenticationProvider.this.logger.debug("User account is locked");
			throw new LockedException(APPAuthenticationProvider.this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked", "User account is locked"));
		} else if (!user.isEnabled()) {
			APPAuthenticationProvider.this.logger.debug("User account is disabled");
			throw new DisabledException(APPAuthenticationProvider.this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled", "User is disabled"));
		} else if (!user.isAccountNonExpired()) {
			APPAuthenticationProvider.this.logger.debug("User account is expired");
			throw new AccountExpiredException(APPAuthenticationProvider.this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.expired", "User account has expired"));
		}
	}

	private void postcheck(UserDetails user) {
		if (!user.isCredentialsNonExpired()) {
			APPAuthenticationProvider.this.logger.debug("User account credentials have expired");
			throw new CredentialsExpiredException(APPAuthenticationProvider.this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.credentialsExpired", "User credentials have expired"));
		}
	}

	private void additionalAuthenticationChecks(UserDetails userDetails, APPAuthenticationToken authentication) throws AuthenticationException {
		Object salt = null;
		if (this.saltSource != null) {
			salt = this.saltSource.getSalt(userDetails);
		}

		if (authentication.getCredentials() == null) {
			this.logger.debug("Authentication failed: no credentials provided");
			throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
		} else {
			String presentedPassword = authentication.getCredentials().toString();
			if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
				this.logger.debug("Authentication failed: password does not match stored value");
				throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
			}
		}
	}

	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
		this.passwordEncoder = passwordEncoder;
	}

	protected PasswordEncoder getPasswordEncoder() {
		return this.passwordEncoder;
	}

	public void setSaltSource(SaltSource saltSource) {
		this.saltSource = saltSource;
	}

	protected SaltSource getSaltSource() {
		return this.saltSource;
	}

	public void setUserDetailsService(UserDetailsService userDetailsService) {
		this.userDetailsService = userDetailsService;
	}

	protected UserDetailsService getUserDetailsService() {
		return this.userDetailsService;
	}
}
